﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Fiuba.Algo3.Titiritero;
using AlgoHero.Modelo;
using System.Xml;
using System.Threading;
using AlgoHero.Vista;
using System.Collections;
using System.ComponentModel;

namespace AlgoHero.Controlador
{
    public class Juego : IObjetoVivo
    {

        private ISuperficieDeDibujo superficieDeDibujo;
        private ControladorJuego controladorJuego;
        private Nivel nivelActual;
        private PreparadorVistaNivel preparadorVistaNivel;
        private ReproductorDeAudio reproductorDeAudio;
        private bool estaJugando;
        private bool estaPausado;
        private bool estaTerminado;

        public bool EstaTerminado
        {
            get { return estaTerminado; }
        }
        private IObservadorDePuntaje observadorDePuntaje;
        private IObservadorDePuntaje observadorDeTeclasPerdidas;
        private Thread hiloAudio;

        public bool EstaJugando
        {
            get { return estaJugando; }
        }

        public bool EstaPausado
        {
            get { return estaPausado; }
        }

        public Juego(ISuperficieDeDibujo superficieDeDibujo)
        {
            this.superficieDeDibujo = superficieDeDibujo;
            this.controladorJuego = new ControladorJuego(this.superficieDeDibujo);
            this.controladorJuego.IntervaloSimulacion = 20;
            this.preparadorVistaNivel = new PreparadorVistaNivel();
            this.reproductorDeAudio = new ReproductorDeAudio();
            this.estaJugando = false;
            this.estaPausado = false;
            this.estaTerminado = false; 
        }

        public void InicializarJuego()
        {
            this.reproductorDeAudio.Encender();
            //this.hiloAudio = null;
            this.hiloAudio = new Thread(new ThreadStart(this.reproductorDeAudio.run));
            this.hiloAudio.Start();
        }

        public void EmpezarAJugarConCancion(string nombreCancion)
        {
            this.PrepararNivel(nombreCancion);
            this.controladorJuego.ComenzarJuego();
            BackgroundWorker delayer = new BackgroundWorker();
            delayer.DoWork += new DoWorkEventHandler(delayer_DoWork);
            delayer.RunWorkerAsync();
        }

        void delayer_DoWork(object sender, DoWorkEventArgs e)
        {
            Thread.Sleep(TimeSpan.FromSeconds(this.preparadorVistaNivel.DameElTiempoParaQueElUsuarioSePrepare().TotalSeconds+0.2));
            this.nivelActual.ComenzarNivel();
            this.estaJugando = true;
        }

        private void PrepararNivel(string nombreCancion)
        {
            // crear la canción
            XmlDocument doc = new XmlDocument();
            XmlTextReader reader = new XmlTextReader(@nombreCancion);
            reader.Read();
            doc.Load(reader);
            Cancion unaCancion = new Cancion(doc);

            // crear un nivel con la canción
            this.nivelActual = new Nivel(unaCancion);

            // preparar el reproductor con datos del nivel
            this.reproductorDeAudio.TiempoFisicoCompas = this.nivelActual.dameElTiempoFisicoDeCompas();
            this.reproductorDeAudio.TiempoMusicalCompas = this.nivelActual.dameElTiempoMusicalDeCompas();

            // preparar la vista del nivel
            this.preparadorVistaNivel.PreparaLaVistaDelNivel(this.nivelActual, unaCancion, this.controladorJuego.IntervaloSimulacion);

            // obtener objetos vivos y dibujables, vistas de puntajes, después de preparar la vista
            IList<IObjetoVivo> objetosVivos = this.preparadorVistaNivel.DameLosObjetosVivos();
            IList<IDibujable> dibujables = this.preparadorVistaNivel.DameLosDibujables();
            this.observadorDePuntaje = this.preparadorVistaNivel.DameElObservadorDePuntaje();
            this.observadorDeTeclasPerdidas = this.preparadorVistaNivel.DameElObservadorDeTeclasPerdidas();

            // agregar al controlador el juego como un objeto vivo
            this.controladorJuego.agregarObjetoVivo(this);

            // agregar todos los objetos vivos y dibujables de la vista del nivel al controlador
            foreach (IObjetoVivo objetoVivo in objetosVivos)
            {
                this.controladorJuego.agregarObjetoVivo(objetoVivo);
            }

            foreach (IDibujable dibujable in dibujables)
            {
                this.controladorJuego.agregarDibujable(dibujable);
            }
        }

        public void PausarJuego()
        {
            if (this.estaJugando)
            {
                this.estaPausado = true;
                this.controladorJuego.DetenerJuego();
                this.nivelActual.PausarNivel();
            }
        }

        public void ReanudarJuego()
        {
            if (this.estaJugando)
            {
                this.estaPausado = false;
                this.controladorJuego.ComenzarJuego();
                this.nivelActual.ReanudarNivel();
            }
        }

        public void TerminarJuego()
        {
            this.estaPausado = false;
            this.estaJugando = false;
            this.estaTerminado = false;
            this.controladorJuego.DetenerJuego();

            IList<IObjetoVivo> objetosVivos = this.preparadorVistaNivel.DameLosObjetosVivos();
            IList<IDibujable> dibujables = this.preparadorVistaNivel.DameLosDibujables();

            this.controladorJuego.removerObjetoVivo(this);

            foreach (IObjetoVivo objetoVivo in objetosVivos)
            {
                this.controladorJuego.removerObjetoVivo(objetoVivo);
            }

            foreach (IDibujable dibujable in dibujables)
            {
                this.controladorJuego.removerDibujable(dibujable);
            }

            this.preparadorVistaNivel.Resetear();
        }

        public void ProcesaTeclasJugadas(IList<Tecla> teclas)
        {
            if (this.estaJugando)
            {
                //if (this.nivelActual.HayParaHacerJugada())
                //{
                    try
                    {
                        this.nivelActual.ProcesaTeclasJugadas(teclas);
                    }
                    catch (TiempoInvalidoException e)
                    {
                        //this.TerminarJuego();
                    }
                //}
            }
        }

        public void Vivir()
        {
            if (this.estaJugando)
            {
                if (this.nivelActual.NivelTerminado)
                {
                    this.estaTerminado = true;
                }
                if (this.nivelActual.HayNotasParaTocar)
                {
                    Acorde acorde = this.nivelActual.dameElAcordeParaTocar();
                    this.reproductorDeAudio.reproducirAcorde(acorde);
                }
                this.nivelActual.ActualizarCantidadDeTeclasPerdidas();
                observadorDePuntaje.seActualizoElPuntaje(this.nivelActual.PuntajeDeNivel);
                observadorDeTeclasPerdidas.seActualizoElPuntaje(this.nivelActual.CantidadDeTeclasPerdidas);
            }
        }
    }
}
